package com.liuzy.controller;

import com.liuzy.config.Const;
import com.liuzy.controller.service.RedisUtil;
import com.liuzy.dto.JsonRet;
import com.liuzy.test.UploadTest;
import com.liuzy.util.FileUtil;
import com.liuzy.vo.FileVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

/**
 * 上传
 */
@Slf4j
@RestController
@RequestMapping("/upload")
public class UploadController {
    @Autowired
    private RedisUtil redisUtil;

    // 分块上传
    @PostMapping("/block")
    public ResponseEntity<JsonRet> block(
            @RequestParam(required = false) String fileId, // 文件ID，如文件名
            @RequestParam(required = false) Long fileLength, // 文件总长度
            @RequestParam(required = false) String blockId, // 块ID，序号
            @RequestParam(required = false) Long blockOffset, // 块起始位置
            @RequestParam(required = false) Long blockLength, // 块长度
            @RequestParam(required = false) String blockMd5, // 块哈希
            @RequestParam(required = false) MultipartFile blockFile, // 块文件
            HttpServletRequest request
    ) throws IOException {
        // 1.文件状态
        File file = FileUtil.absoluteFile(fileId); // 文件真实路径
        if (file.exists()) {
            FileVo fileVo = new FileVo();
            fileVo.setId(fileId);
            fileVo.setLength(file.length());
            fileVo.setUtime(file.lastModified());
            return JsonRet.ok(fileVo);
        }
        // 临时文件
        File temp = FileUtil.gotTempFile(fileId, fileLength);
        // 2.块状态
        String md5 = redisUtil.hget(Const.FILE_BLOCKS + fileId, blockId);
        log.info("块 {} 缓存值 {}", blockId, md5);
        if (!StringUtils.hasText(md5) || !md5.equals(blockMd5)) {
            // 3.写块
            log.info("写块 {} 位置 {} 长度 {}", blockId, blockOffset, blockLength);
            if (FileUtil.writeTempFile(temp, blockFile, blockOffset)) {
                redisUtil.hset(Const.FILE_BLOCKS + fileId, blockId, blockMd5);
            }
            // 4.是否已全部完成
            long count = redisUtil.hlen(Const.FILE_BLOCKS + fileId);
            long total = FileUtil.slice(fileLength, blockLength);
            log.info("当前已完成 {}/{}", count, total);
            if (count > 0 && count == total) {
                log.info("所有块 {} 已完成，重命名文件。", total);
                if (temp.renameTo(file)) {
                    return JsonRet.ok();
                } else {
                    log.error("所有块已完成，但重命名时失败！");
                }
            }
        }
        // 5.返回前块的信息
        return JsonRet.ok(blockId);
    }

    @GetMapping("/test")
    public void test() {
        new UploadTest().test();
    }
}
